#ifndef _OPTION_H_
#define _OPTION_H_

#include <getopt.h>

/* La estructura option2 contiene los parámetros posibles a indicar en línea de comandos.
 * \param opts.main contiene el nombre del parámetro, tal y como se debe indicar en la línea de comandos
 * \param opts.has_arg valdrá 0, 1 ó 2 si el parámetro no puede tener argumentos, sí debe tenerlos o es opcional
 * \param opts.flags debe ser NULL.

 * \param opts.val Puede tomar alguno de los valores true, false, OPT_VAL_IS_INT, OPT_VAL_IS_CHAR, OPT_AFFECT_OTHER u OPT_NEG_OTHER.
 * si opts.val= true ó false: El parámetro tomará el boolen indicado en el caso de ser indicado como parámetro de entrada en la línea de comandos. Si no se indica en la llamada, tomará el valor por defecto. El valor opts.has_arg debe ser 0.
 * si opts.val= OPT_VAL_IS_INT ó OPT_VAL_IS_CHAR: El parámetro tomará el valor intero o char que se indique en la línea de comandos, o el valor por defecto si no aparece. opts.has_arg debe ser 1 ó 2.
 * si opts.val= OPT_AFFECT_OTHER: el parámetro es un sinónimo del parámetro referenciado por el offset indicado en inival.
 * si opts.val= OPT_NEG_OTHER: el parámetro es la negación de otro referenciado por el offset indicado en inival.

 * \param inival Valor entero por defecto para el parámetro, u offset en el caso de que opts.val sea OPT_NEG_OTHER u OPT_AFFECT_OTHER
 * \param inichar Cadena de caracteres con el valor inicial del parámetro
 * \param description Texto a mostrar en la ayuda
 */

#define OPT_VAL_IS_INT 3 //para indicar que el parámetro identifica a un entero
#define OPT_VAL_IS_CHAR 4 //el parámetro es un cadena de caracteres
#define OPT_AFFECT_OTHER 5 //el parametro es un sinónimo de otro, indicado como un offset en option2.inival
#define OPT_NEG_OTHER 6 //el parametro es la negación de otro,  indicado como un offset en option2.inival. Éste otro normalmente será de tipo boll: option2.opt.val = TRUE ó FALSE.

#define MAX_ARGUMENT_VAL 100 //longitud máxima del argumento que se puede indicar por línea de commando

//estructura para indicar los posibles parámetros de entrada, y opciones
struct option2 {
    struct option opts; //similar a options de getlong_opt. flag debe ser NULL.
    int inival; //valor por defecto, u offset si opts.val = OPT_NEG_OTHER ú OPT_AFFECT_OTHER
    char inichar[MAX_ARGUMENT_VAL]; //valor por defecto
    const char *description; //texto a mostrar en la ayuda
};


/* Ejemplo de extructura option2. Los parámtros opt, help y h son obligatorios: 
struct option2 mainopts2[]= {

    {{"focus", 0, NULL, true}, false, "", 
     ""},
    {{"nofocus", 0, NULL, OPT_NEG_OTHER}, -1 , "", 
     "Indica si mostrar una ventana que pide el enfoque manual de las cámaras"}, 

    {{"path", 1, NULL, OPT_AFFECT_OTHER}, 1, "", 
     ""},
    {{"videopath", 1, NULL, OPT_VAL_IS_CHAR}, 0, "", 
     "Directorio donde guardar los videos de la primera y segunda cámara" },

    {{"light", 1, NULL, OPT_VAL_IS_INT}, 15, "",
     "Valor inicial de intensidad luminosa infrarroja"}, 
    {{"gain", 1, NULL, OPT_VAL_IS_INT}, 0, "",
     "Valor inicial de ganancia, en unidades de la cámara"}, 

    {{"options", 0, NULL, true}, false, "", 
     "Imprime por pantalla las opciones de configuracion del programa"},
    {{"h", 0, NULL, true}, false, "", 
     ""},
    {{"help", 0, NULL, true}, false, "", 
     "Muestra las opciones que se pueden indicar por línea de comandos"},
    {{NULL, 0, NULL, 0}, 0, "", 
     ""}
};
*/


/* \brief Devuelve el valor (int) del parámetro de línea de comando indicado en clave. El parámetro debe tener el valor OPT_VAL_IS_INT en el campo mainopts2.opts.val (cuarto parámetro)
 * \param Clave debe coincidir con el parámetro tal y como se aparece en la extructura mainopts
 * \param Next No devuelve el valor del parámetro clave, sino del parámetro situado 
next veces después de clave en la extructura mainopts2
 * \return el valor del parámetro. Basura si el parámetro no es de tipo OPT_VAL_IS_INT
 */
int ini_opt(const char * clave, int next=0);

/* \brief Devuelve el valor (cadena de caracteres) del  parámetro de línea de comando indicado en clave. El parámetro debe tener el valor OPT_VAL_IS_CHAR en el campo mainopts2.opts.val (cuarto parámetro)
 * \param Clave debe coincidir con el parámetro tal y como se aparece en la extructura mainopts
 * \param Next No devuelve el valor del parámetro clave, sino del parámetro situado 
next veces después de clave en la extructura mainopts2
 * \return Un puntero a una cadena de caracteres con el argumento pasado. Basura si el parámetro no es de tipo OPT_VAL_IS_CHAR
 */
const char * ini_opts(const char * clave, int next=0);

/* \brief Establece el valor (int) del  parámetro de línea de comando indicado en clave. El parámetro debe tener el valor OPT_VAL_IS_INT en el campo mainopts2.opts.val (cuarto parámetro)
 * \param Clave debe coincidir con el parámetro tal y como se aparece en la extructura mainopts
 * \param val Nuevo valor para el parámetro
 * \param Next No devuelve el valor del parámetro clave, sino del parámetro situado 
next veces después de clave en la extructura mainopts2
 * \return el valor anterior del parámetro. Basura si el parámetro no es de tipo OPT_VAL_IS_INT
 */
int ini_setopt(const char * clave, int val, int next=0);

/* \brief Establece el valor (cadena de caracteres) del  parámetro de línea de comando indicado en clave. El parámetro debe tener el valor OPT_VAL_IS_CHAR en el campo mainopts2.opts.val (cuarto parámetro)
 * \param Clave debe coincidir con el parámetro tal y como se aparece en la extructura mainopts
 * \param Next No devuelve el valor del parámetro clave, sino del parámetro situado 
next veces después de clave en la extructura mainopts2
 * \param val Nueva cadena de caracteres como argumento para el parámetro indicado en clave + next
 * \return Un puntero a una caracteres con el nuevo argumento pasado para el parámetro. Basura si el parámetro no es de tipo OPT_VAL_IS_CHAR
 */
const char * ini_setopts(const char * clave, const char * val, int next=0);

/* \brief Inicializa la lectura de los parámetros de línea de comandos
 * \param argc argc del main
 * \param argv argv del main
 * \param ini_file Archivo que contiene más parámetro a pasar al ejecutable. Estos se leen antes que los parámetros escritos en línea de comandos, y por tanto, los últimos sobreescriben a los del archivo. 
 * \return 0 si se indicó llamada a los parámetros --help o -h. 1 en otro caso.
 */
int leer_opciones(int argc, char * argv[], const char * ini_file = NULL);

/* \brief Borrar todo el espacio de memoria reservado para la lectura y almacenamiento de los parámetros de línea de comandos
 */
void fin_opciones();


#endif
